/////////////////////////////////////////////////////////////////////////////
// Name:        ax_menu_range.cpp
// Purpose:     Range menu class
// Author:      Julian Smart
// Modified by:
// Created:     2009-03-20
// RCS-ID:
// Copyright:   (c) Julian Smart
// Licence:     New BSD License
/////////////////////////////////////////////////////////////////////////////

#include "wx/wx.h"
#include "wx/spinctrl.h"

#include "ax/ax_menu_range.h"
#include "ax/ax_menu_alert.h"
#include "ax/ax_textinputdialog.h"
/*!
 * AxRangeActivator implementation.
 * Sets the value of a boolean variable when toggled.
 */

IMPLEMENT_DYNAMIC_CLASS( AxRangeActivator, AxAutoUpdateActivator )

AxRangeActivator::AxRangeActivator(
        const wxString& labelSpec,
        const wxString& descriptionSpec,
        AxRangeCommand cmd,
        AxRangeActivator* mainActivator,
        AxMenuController* controller,
        AxMenuItem* item):
  AxAutoUpdateActivator(labelSpec, descriptionSpec)
{
    Init();

    m_command = cmd;
    m_mainActivator = mainActivator;
    m_controller = controller;
    m_item = item;
}

void AxRangeActivator::Init()
{
    m_mainActivator = NULL;
    m_command = AxRangeCommandUnknown;
    m_controller = NULL;
    m_item = NULL;
}

AxRangeMenuItem* AxRangeActivator::GetRangeMenuItem() const
{
    if (m_item)
        return wxDynamicCast(m_item, AxRangeMenuItem);
    else
        return wxDynamicCast(GetMenuItem(), AxRangeMenuItem);
}

void AxRangeActivator::Copy(const AxRangeActivator& activator)
{
    AxAutoUpdateActivator::Copy(activator);

    m_mainActivator = activator.m_mainActivator;
    m_command = activator.m_command;
    m_controller = activator.m_controller;
    m_item = activator.m_item;
}

AxMenu* AxRangeActivator::Activate(AxMenuController* controller, AxMenuItem* item)
{
    if (m_command == AxRangeCommandUp)
    {
        BumpValue(1);
    }
    else if (m_command == AxRangeCommandDown)
    {
        BumpValue(-1);
    }
    else if (m_command == AxRangeCommandEnterValue)
    {
        EnterValue();
    }
    else if (m_command == AxRangeCommandMain)
    {
        AxRangeMenuItem* rangeItem = GetRangeMenuItem();

        // Create a menu
        AxMenu* menu = new AxMenu(_("Range"),
            wxString::Format(_("Increase or decrease the value, or enter a value between %d and %d."), rangeItem->GetMinValue(), rangeItem->GetMaxValue()));
        
        AxMenuItem* child = new AxMenuItem(_("Decrease (%VALUE%)"), _("Decrement the value."), wxT("DECREMENT"),
            new AxRangeActivator(_("Decrease (%VALUE%)"), _("Decrement the value."), AxRangeCommandDown, this,
                                controller, item));
        child->GetActivator()->SetMenuItem(child);
        child->SetStyle(AxMenuStyleBold);
        menu->AddItem(child);
        
        child = new AxMenuItem(_("Increase (%VALUE%)"), _("Increment the value."), wxT("INCREMENT"),
            new AxRangeActivator(_("Increase (%VALUE%)"), _("Increment the value."), AxRangeCommandUp, this,
                                controller, item));
        child->GetActivator()->SetMenuItem(child);
        child->SetStyle(AxMenuStyleBold);
        menu->AddItem(child);
        
        wxString textLabel = _("Enter number (%VALUE%)");
        wxString textDescription = wxString::Format(_("Enter a number between %d and %d."), rangeItem->GetMinValue(), rangeItem->GetMaxValue());
        textDescription += _(" The current value  is %VALUE%.");
        child = new AxMenuItem(textLabel,
            textDescription,
            wxT("ENTERTEXT"),
            new AxRangeActivator(textLabel, textDescription, AxRangeCommandEnterValue, this,
                                controller, item));
        child->GetActivator()->SetMenuItem(child);
        child->SetStyle(AxMenuStyleBold);
        menu->AddItem(child);
        
        // Add an 'Up' item
        menu->AddItem(new AxGoUpMenuItem);
        
        return menu;
    }
    
    return NULL;
}

wxString AxRangeActivator::CreateString(const wxString& spec, bool isLabel)
{
    AxRangeMenuItem* rangeItem = GetRangeMenuItem();
    if (rangeItem)
        return rangeItem->CreateString(spec, isLabel);
    else
        return wxEmptyString;
}

// Increase or decrease value
bool AxRangeActivator::BumpValue(int by)
{
    AxRangeMenuItem* rangeItem = GetRangeMenuItem();
    if (rangeItem)
    {
        int newValue = (rangeItem->GetValue() + by);
        if (newValue >= rangeItem->GetMinValue() && newValue <= rangeItem->GetMaxValue())
        {
            rangeItem->SetValue(newValue);
            rangeItem->SendRangeUpdate(newValue);

            return true;
        }
    }
    return false;
}

// Prompt user to enter value
bool AxRangeActivator::EnterValue()
{
    AxRangeMenuItem* rangeItem = GetRangeMenuItem();
    if (rangeItem)
    {
        wxString defaultValue(wxString::Format(wxT("%d"), rangeItem->GetValue()));
        wxString message(wxString::Format(_("Please enter a value between %d and %d."),
            rangeItem->GetMinValue(), rangeItem->GetMaxValue()));
        wxString caption(_("Numeric Input"));
        AxTextInputDialog dialog(NULL, message, caption, defaultValue);
        if (dialog.ShowModal() == wxID_OK)
        {
            wxString newValue = dialog.GetValue();
            if (newValue != defaultValue)
            {
                int newIntValue = wxAtoi(newValue);
                if (newIntValue >= rangeItem->GetMinValue() && newIntValue <= rangeItem->GetMaxValue())
                {
                    rangeItem->SetValue(newIntValue);
                    rangeItem->SendRangeUpdate(newIntValue);

                    return true;
                }
                else
                {
                    AxModalAlertMenu alert(m_controller, m_item,
                        _("Incorrect range value"),
                        wxString::Format(_("Sorry, %d was not within %d and %d. Select this item to continue."),
                        newIntValue,
                        rangeItem->GetMinValue(),
                        rangeItem->GetMaxValue()),
                        _("Incorrect range value"),
                        axALERT_NO_BUTTONS);

                    alert.ShowModal();
                    
                    return false;
                }
            }
            else
                return true;
        }
        else
            return false;
    }
    return true;
}


/*!
 * AxRangeMenuItem implementation.
 */

IMPLEMENT_DYNAMIC_CLASS( AxRangeMenuItem, AxMenuItem )

AxRangeMenuItem::AxRangeMenuItem(const wxString& label, const wxString& description,
        const wxString& id,
        int minValue,
        int maxValue,
        int value)
{
    Create(label, description, id, minValue, maxValue, value);
}

bool AxRangeMenuItem::Create(const wxString& label, const wxString& description,
        const wxString& id,
        int minValue,
        int maxValue,
        int value)
{
    SetLabel(label);
    SetKind(_("range"));
    SetDescription(description);
    SetId(id);
    SetDynamic();

    m_minValue = minValue;
    m_maxValue = maxValue;
    m_value = value;

    AxRangeActivator* activator =
        new AxRangeActivator(label, description,
        AxRangeActivator::AxRangeCommandMain, NULL, NULL, NULL);
    SetActivator(activator);

    return true;
}

void AxRangeMenuItem::Copy(const AxRangeMenuItem& item)
{
    AxMenuItem::Copy(item);

    m_minValue = item.m_minValue;
    m_maxValue = item.m_maxValue;
    m_value = item.m_value;
}

wxString AxRangeMenuItem::CreateString(const wxString& spec, bool WXUNUSED(isLabel))
{
    wxString value = wxString::Format(wxT("%d"), m_value);
    wxString minValue(wxString::Format(wxT("%d"), m_minValue));
    wxString maxValue(wxString::Format(wxT("%d"), m_maxValue));
    wxString str = spec;
    str.Replace(wxT("%VALUE%"), value);
    str.Replace(wxT("%MINVALUE%"), minValue);
    str.Replace(wxT("%MAXVALUE%"), maxValue);
    return str;
}

void AxRangeMenuItem::SetValue(int value)
{
    m_value = value;

    TransferDataFromMenu();
}

void AxRangeMenuItem::SendRangeUpdate(int value)
{
    wxCommandEvent event(wxEVT_COMMAND_SPINCTRL_UPDATED, AxGetId(GetId()));
    event.SetEventObject(this);
    event.SetInt(value);

    ProcessEvent(event);
}

IMPLEMENT_DYNAMIC_CLASS( AxRangeValidator, AxValidator )

// Override to pass a value from the UI to a data structure
bool AxRangeValidator::TransferDataFromMenu()
{
    AxRangeMenuItem* rangeItem = wxDynamicCast(GetMenuItem(), AxRangeMenuItem);
    if (rangeItem)
    {
        if (m_intPtr)
            * m_intPtr = rangeItem->GetValue();
    }

    return true;
}

// Override to pass a value from a data structure to the UI
bool AxRangeValidator::TransferDataToMenu()
{
    AxRangeMenuItem* rangeItem = wxDynamicCast(GetMenuItem(), AxRangeMenuItem);
    if (rangeItem)
    {
        if (m_intPtr)
            rangeItem->SetValue(* m_intPtr);
    }

    return true;
}

